/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package session.stateful;

import entity.BranchEntity;
import entity.FnBBranchEntity;
import entity.FnBReservationEntity;
import entity.PersonEntity;
import entity.ReservationEntity;
import entity.ReservedMealEntity;
import entity.ReservedSetMealEntity;
import entity.StakeholderEntity;
import entity.TouristAccountEntity;
import entity.TouristEntity;
import entity.UserAccountEntity;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import javax.ejb.Stateful;
import javax.ejb.LocalBean;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import util.enumeration.Country;
import util.enumeration.Gender;

/**
 *
 * @author Dao Thai Duy
 */
@Stateful
@LocalBean
public class TouristSessionBean {

    @PersistenceContext
    private EntityManager entityManager;
    private StakeholderSessionBeanStateful stakeholderSessionBean;

    public List<PersonEntity> getAllTourists() {
        Query query = getEntityManager().createQuery("SELECT c FROM Person c");
        return query.getResultList();
    }

    public List<TouristAccountEntity> getTouristByEmail(String email) {
        Query query = entityManager.createQuery("SELECT c FROM TouristAccountEntity c WHERE c.tourist.email= :email");
        query.setParameter("email", email);
        return query.getResultList();
    }

    public List<String> getAllEmails() {
        Query query = getEntityManager().createQuery("SELECT c.email FROM TouristAccountEntity c");
        return query.getResultList();
    }

    public TouristAccountEntity getTouristById(Long id) {
        return entityManager.find(TouristAccountEntity.class, id);
    }

    public TouristAccountEntity getTouristByUsername(String username) {
        Query query = entityManager.createQuery("SELECT c FROM UserAccount c WHERE c.username = :username");
        query.setParameter("username", username);
        try {
            return (TouristAccountEntity) query.getSingleResult();
        } catch (Exception e) {
            System.out.println("No such user !!!");
            return null;
        }
    }

    //Duy-start
    public void addTestTourist() {
        TouristEntity tourist = new TouristEntity();
        Date date = new Date();
        tourist.create("Duy", "Dao Thai", Gender.MALE, date, Country.SINGAPORE, "nothing", "daothaiduy@gmail.com", "nothing");
        System.out.println("addTestTourist");
        entityManager.persist(tourist);
    }

    public List<UserAccountEntity> getAllUserAccount() {
        System.out.println("getAllUserAccount");
        Query query = getEntityManager().createQuery("SELECT u FROM UserAccount u");
        System.out.println("UserAccountList " + query.getResultList().size());
        return query.getResultList();
    }

    public List<TouristAccountEntity> getAllCustomerAccount() {
        int i;
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        for (i = 0; i < getAllUserAccount().size(); i++) {
            if (getAllUserAccount().get(i) instanceof TouristAccountEntity) {
                TouristAccountEntity tempTouristAccount = (TouristAccountEntity) getAllUserAccount().get(i);
                customerAccountList.add(tempTouristAccount);
            }
        }
        System.out.println("CustomerAccountList " + customerAccountList.size());
        return customerAccountList;
    }

    public List<TouristAccountEntity> getAllTouristAccount() {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<TouristAccountEntity> touristAccountList = new ArrayList<TouristAccountEntity>();
        customerAccountList = getAllCustomerAccount();
        for (TouristAccountEntity t : customerAccountList) {
            if (t.getTourist().getCountry() != Country.SINGAPORE) {
                touristAccountList.add(t);
            }
        }
        return touristAccountList;
    }

    public List<TouristAccountEntity> getAllLocalAccount() {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<TouristAccountEntity> localAccountList = new ArrayList<TouristAccountEntity>();
        customerAccountList = getAllCustomerAccount();
        for (TouristAccountEntity t : customerAccountList) {
            if (t.getTourist().getCountry() == Country.SINGAPORE) {
                localAccountList.add(t);
            }
        }
        return localAccountList;
    }

    public List<TouristAccountEntity> getCustomerAccountOfStakeholder(StakeholderEntity stakeholder, Date date1, Date date2) {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<BranchEntity> branchList = new ArrayList<BranchEntity>();

        System.out.println("4a");
        branchList = stakeholder.getBranches();
        System.out.println("4b");
        for (BranchEntity b : branchList) {
            System.out.println("4c");
            List<ReservationEntity> tempReservationList = b.getReservation();
            System.out.println("4d");
            for (ReservationEntity r : tempReservationList) {
                System.out.println("4e");
                if (r instanceof FnBReservationEntity) {
                    System.out.println("4f");
                    FnBReservationEntity tempFnBReservation = (FnBReservationEntity) r;
                    System.out.println(tempFnBReservation.getDateReserved());
                    System.out.println(date1);
                    System.out.println(date2);
                    if (tempFnBReservation.getDateReserved().compareTo(date1) >= 0
                            && tempFnBReservation.getDateReserved().compareTo(date2) <= 0
                            && tempFnBReservation.getStatus() != null && tempFnBReservation.getStatus().compareTo("Show") == 0) {
                        System.out.println("4g");
                        customerAccountList.add(tempFnBReservation.getTourist());
                    }
                }
            }
        }
        return customerAccountList;
    }

    public List<TouristAccountEntity> getDistinctCustomerAccountOfStakeholder(StakeholderEntity stakeholder, Date date1, Date date2) {
        return removeDuplicate(getCustomerAccountOfStakeholder(stakeholder, date1, date2));
    }

    public List<TouristAccountEntity> getDistinctCustomerAccountOfStakeholder(StakeholderEntity stakeholder) {
        return removeDuplicate(getCustomerAccountOfStakeholder(stakeholder));
    }

    public List<TouristAccountEntity> getLocalAccountOfStakeholder(StakeholderEntity stakeholder, Date date1, Date date2) {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<TouristAccountEntity> localAccountList = new ArrayList<TouristAccountEntity>();

        System.out.println("3a");
        customerAccountList = getCustomerAccountOfStakeholder(stakeholder, date1, date2);
        System.out.println("3b");
        System.out.println(localAccountList.size());
        for (TouristAccountEntity t : customerAccountList) {
            System.out.println("3c");
            if (t.getTourist().getCountry() == Country.SINGAPORE) {
                System.out.println("3d");
                localAccountList.add(t);
            }
        }
        System.out.println("end local account of stakeholder");
        return localAccountList;
    }

    public List<TouristAccountEntity> getLocalAccountOfStakeholder(StakeholderEntity stakeholder) {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<TouristAccountEntity> localAccountList = new ArrayList<TouristAccountEntity>();

        customerAccountList = getCustomerAccountOfStakeholder(stakeholder);
        System.out.println(localAccountList.size());
        for (TouristAccountEntity t : customerAccountList) {
            if (t.getTourist().getCountry() == Country.SINGAPORE) {
                localAccountList.add(t);
            }
        }
        return localAccountList;
    }

    public List<TouristAccountEntity> getDistinctLocalAccountOfStakeholder(StakeholderEntity stakeholder, Date date1, Date date2) {
        System.out.println("1a");
        System.out.println("date1 " + date1);
        System.out.println("date2 " + date2);
        return removeDuplicate(getLocalAccountOfStakeholder(stakeholder, date1, date2));
    }

    public List<TouristAccountEntity> getDistinctLocalAccountOfStakeholder(StakeholderEntity stakeholder) {
        System.out.println("2a");
        return removeDuplicate(getLocalAccountOfStakeholder(stakeholder));
    }

    public List<TouristAccountEntity> getTouristAccountOfStakeholder(StakeholderEntity stakeholder, Date date1, Date date2) {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<TouristAccountEntity> touristAccountList = new ArrayList<TouristAccountEntity>();

        customerAccountList = getCustomerAccountOfStakeholder(stakeholder, date1, date2);
        for (TouristAccountEntity t : customerAccountList) {
            if (t.getTourist().getCountry() != Country.SINGAPORE) {
                touristAccountList.add(t);
            }
        }
        return touristAccountList;
    }

    public List<TouristAccountEntity> getTouristAccountOfStakeholder(StakeholderEntity stakeholder) {
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();
        List<TouristAccountEntity> touristAccountList = new ArrayList<TouristAccountEntity>();

        customerAccountList = getCustomerAccountOfStakeholder(stakeholder);
        for (TouristAccountEntity t : customerAccountList) {
            if (t.getTourist().getCountry() != Country.SINGAPORE) {
                touristAccountList.add(t);
            }
        }
        return touristAccountList;
    }

    public List<TouristAccountEntity> getDistinctTouristAccountOfStakeholder(StakeholderEntity stakeholder, Date date1, Date date2) {
        return removeDuplicate(getTouristAccountOfStakeholder(stakeholder, date1, date2));
    }

    public List<TouristAccountEntity> getDistinctTouristAccountOfStakeholder(StakeholderEntity stakeholder) {
        return removeDuplicate(getTouristAccountOfStakeholder(stakeholder));
    }

    public List<String> getLocaleList(StakeholderEntity stakeholder, Date date1, Date date2) {
        List<String> localeList = new ArrayList<String>();

        for (TouristAccountEntity t : getLocalAccountOfStakeholder(stakeholder, date1, date2)) {
            localeList.add(t.getTourist().getLocale());
        }
        return localeList;
    }

    public List<String> getCountryList(StakeholderEntity stakeholder, Date date1, Date date2) {
        List<String> countryList = new ArrayList<String>();
        for (TouristAccountEntity t : getTouristAccountOfStakeholder(stakeholder, date1, date2)) {
            countryList.add(t.getTourist().getCountry().toString());
        }
        return countryList;
    }

    public List removeDuplicate(List arlList) {
        HashSet h = new HashSet(arlList);
        arlList.clear();
        arlList.addAll(h);
        return arlList;
    }
    //AcquitistionRate-end  

    //CustomerLifeTimeValue-start
    public Double getSpendingOfReservation(ReservationEntity reservation) {
        Double spending = 0.0;

        if (reservation instanceof FnBReservationEntity) {
            FnBReservationEntity fnbReservation = (FnBReservationEntity) reservation;
            if (fnbReservation.getReservedTable() != null) {
                for (ReservedMealEntity meal : fnbReservation.getReservedMeal()) {
                    spending += meal.getPrice() * meal.getQuantity();
                }

                for (ReservedSetMealEntity set : fnbReservation.getReservedSetMeal()) {
                    spending += set.getPrice() * set.getQuantity();
                }

            }
        }
        return spending;
    }

    public List<Double> getCustomerSpendingList(StakeholderEntity stakeholder, Date date1, Date date2) {
        List<Double> customerSpendingList = new ArrayList<Double>();
        List<TouristAccountEntity> customerAccountList = new ArrayList<TouristAccountEntity>();

        customerAccountList = getDistinctCustomerAccountOfStakeholder(stakeholder, date1, date2);
        for (TouristAccountEntity t : customerAccountList) {
            List<ReservationEntity> reservationList = new ArrayList<ReservationEntity>();
            reservationList = t.getReservation();
            for (ReservationEntity r : reservationList) {
                double spending = getSpendingOfReservation(r);
                customerSpendingList.add(spending);
            }          
        }
        return customerSpendingList;
    }

    public List<ReservationEntity> getReservationOfStakeholder(StakeholderEntity stakeholder) {
        List<BranchEntity> branchList = new ArrayList<BranchEntity>();
        List<ReservationEntity> reservationList = new ArrayList<ReservationEntity>();

        branchList = stakeholder.getBranches();
        for (BranchEntity b : branchList) {
            List<ReservationEntity> tempReservationList = new ArrayList<ReservationEntity>();
            tempReservationList = b.getReservation();
            reservationList.addAll(tempReservationList);
        }
        return reservationList;
    }

    public List<ReservationEntity> getLocalReservationOfStakeholder(StakeholderEntity stakeholder) {
        List<ReservationEntity> localReservationList = new ArrayList<ReservationEntity>();

        for (ReservationEntity r : getReservationOfStakeholder(stakeholder)) {
            if (r.getTourist().getTourist().getCountry() == Country.SINGAPORE) {
                localReservationList.add(r);
            }
        }
        return localReservationList;
    }

    public List<ReservationEntity> getTouristReservationOfStakeholder(StakeholderEntity stakeholder) {
        List<ReservationEntity> touristReservationList = new ArrayList<ReservationEntity>();

        for (ReservationEntity r : getReservationOfStakeholder(stakeholder)) {
            if (r.getTourist().getTourist().getCountry() != Country.SINGAPORE) {
                touristReservationList.add(r);
            }
        }
        return touristReservationList;
    }

    public Double getAverageNumReservationLocal(StakeholderEntity stakeholder) {
        Double averageReservationLocal = 0.0, numReservation = 0.0, numAccount = 0.0;
        List<TouristAccountEntity> localAccountList = new ArrayList<TouristAccountEntity>();
        List<ReservationEntity> reservationList = new ArrayList<ReservationEntity>();

        localAccountList = getDistinctLocalAccountOfStakeholder(stakeholder);
        reservationList = getLocalReservationOfStakeholder(stakeholder);
        numReservation = Double.valueOf(reservationList.size());
        numAccount = Double.valueOf(localAccountList.size());
        if (numAccount != 0) {
            averageReservationLocal = numReservation / numAccount;
        }
        return averageReservationLocal;
    }

    public Double getAverageNumReservationTourist(StakeholderEntity stakeholder) {
        Double averageReservationTourist = 0.0, numReservation = 0.0, numAccount = 0.0;
        List<TouristAccountEntity> touristAccountList = new ArrayList<TouristAccountEntity>();
        List<ReservationEntity> reservationList = new ArrayList<ReservationEntity>();

        touristAccountList = getDistinctTouristAccountOfStakeholder(stakeholder);
        reservationList = getTouristReservationOfStakeholder(stakeholder);
        numReservation = Double.valueOf(reservationList.size());
        numAccount = Double.valueOf(touristAccountList.size());
        averageReservationTourist = numReservation / numAccount;
        return averageReservationTourist;
    }

    public Double getAverageReservationIntervalLocal(StakeholderEntity stakeholder) {
        List<TouristAccountEntity> localAccountList = new ArrayList<TouristAccountEntity>();
        Double totalInterval = 0.0;
        Double averageInterval = 0.0;
        Double numInterval = 0.0;
        int i;

        localAccountList = getDistinctLocalAccountOfStakeholder(stakeholder);
        for (TouristAccountEntity t : localAccountList) {
            List<ReservationEntity> tempReservationList = new ArrayList();
            Date minDate = new Date();
            Date maxDate = new Date();

            tempReservationList = t.getReservation();
            if (tempReservationList.size() >= 2) {
                FnBReservationEntity tempfnbReservation = (FnBReservationEntity) tempReservationList.get(0);
                minDate = tempfnbReservation.getDateReserved();
                maxDate = tempfnbReservation.getDateReserved();
                for (ReservationEntity r : tempReservationList) {
                    FnBReservationEntity fnb = (FnBReservationEntity) r;
                    if (fnb.getDateReserved().compareTo(maxDate) >= 0) {
                        maxDate = fnb.getDateReserved();
                    }
                    if (fnb.getDateReserved().compareTo(minDate) <= 0) {
                        minDate = fnb.getDateReserved();
                    }
                }
            }
            int date1 = minDate.getDate();
            int month1 = minDate.getMonth();
            int year1 = minDate.getYear();
            int date2 = maxDate.getDate();
            int month2 = maxDate.getMonth();
            int year2 = maxDate.getYear();
            while (month1 != month2 || year1 != year2) {
                totalInterval += getMaxDayOfMonth(month1, year1);
                month1 = (month1 + 1) % 12;
                if (month1 == 0) {
                    year1++;
                }
            }
            totalInterval += date2 - date1;
            numInterval += tempReservationList.size() - 1;
        }
        System.out.println("abc");
        if (numInterval != 0) {
            averageInterval = totalInterval / numInterval;
        }
        return averageInterval;
    }

    private int getMaxDayOfMonth(int month, int year) {
        switch (month) {
            case 0:
            case 2:
            case 4:
            case 6:
            case 7:
            case 9:
            case 11:
                return 31;
            case 1:
                if (isLeapYear(year)) {
                    return 29;
                } else {
                    return 28;
                }
            default:
                return 30;
        }
    }

    private boolean isLeapYear(int year) {
        if (year % 400 == 0) {
            return true;
        }
        if (year % 100 == 0) {
            return false;
        }
        if (year % 4 == 0) {
            return true;
        }
        return false;
    }

    public Double getAverageReservationIntervalTourist(StakeholderEntity stakeholder) {
        List<TouristAccountEntity> touristAccountList = new ArrayList<TouristAccountEntity>();
        Double totalInterval = 0.0;
        Double averageInterval = 0.0;
        Double numInterval = 0.0;
        int i;

        touristAccountList = getDistinctTouristAccountOfStakeholder(stakeholder);
        for (TouristAccountEntity t : touristAccountList) {
            List<ReservationEntity> tempReservationList = new ArrayList();
            Date minDate = new Date();
            Date maxDate = new Date();

            tempReservationList = t.getReservation();
            if (tempReservationList.size() >= 2) {
                FnBReservationEntity tempfnbReservation = (FnBReservationEntity) tempReservationList.get(0);
                minDate = tempfnbReservation.getDateReserved();
                maxDate = tempfnbReservation.getDateReserved();
                for (ReservationEntity r : tempReservationList) {
                    FnBReservationEntity fnb = (FnBReservationEntity) r;
                    if (fnb.getDateReserved().compareTo(maxDate) >= 0) {
                        maxDate = fnb.getDateReserved();
                    }
                    if (fnb.getDateReserved().compareTo(minDate) <= 0) {
                        minDate = fnb.getDateReserved();
                    }
                }
            }
            totalInterval += (maxDate.getTime() - minDate.getTime()) / (1000 * 60 * 60 * 24);
            numInterval += tempReservationList.size() - 1;
        }
        averageInterval = totalInterval / numInterval;
        return averageInterval;
    }
    //CustomerLifeTImeValue-end  
//Duy-end

    public EntityManager getEntityManager() {
        return entityManager;
    }

    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public StakeholderSessionBeanStateful getStakeholderSessionBean() {
        return stakeholderSessionBean;
    }

    public void setStakeholderSessionBean(StakeholderSessionBeanStateful stakeholderSessionBean) {
        this.stakeholderSessionBean = stakeholderSessionBean;
    }
    
    //Hieu-start
     public List<TouristAccountEntity> getCustomerAccountOfStakeholder(StakeholderEntity stakeholder){
        List<TouristAccountEntity> touristAccountList= new ArrayList<TouristAccountEntity>();
        List<BranchEntity> branchList= new ArrayList<BranchEntity>();       
        branchList=stakeholder.getBranches();   
        for(BranchEntity b:branchList){
            List<ReservationEntity> tempReservationList= b.getReservation();
            for(ReservationEntity r:tempReservationList)
                if(r instanceof FnBReservationEntity){
                    FnBReservationEntity tempFnBReservation= (FnBReservationEntity)r;
                    if(tempFnBReservation.getStatus() !=null && tempFnBReservation.getStatus().equalsIgnoreCase("Show")){
                        touristAccountList.add(tempFnBReservation.getTourist());
                    }
                }
        }
        return touristAccountList;         
     }
     
     public List<TouristAccountEntity> getReturneeOfStakeholder(StakeholderEntity stakeholder){
         List<TouristAccountEntity> returneeList= new ArrayList<TouristAccountEntity>(); // for returnees
         List<TouristAccountEntity> customerList = new ArrayList<TouristAccountEntity>(); // for all customers
         List<TouristAccountEntity> tempList = new ArrayList<TouristAccountEntity>(); // for customers that are not returnees
         
         customerList = getCustomerAccountOfStakeholder (stakeholder);

        for (TouristAccountEntity t : customerList) {
            if (!tempList.contains(t) && !returneeList.contains(t)) {
                tempList.add(t);
            } else if (tempList.contains(t) && !returneeList.contains(t)) {
                returneeList.add(t);
                tempList.remove(t);
            } else if (!tempList.contains(t) && returneeList.contains(t)) {
            }
        }      
         return returneeList;
     }
     
//Hieu-end    

}
